#!/bin/bash
# Copyright (c) 2020 maminjie <maminjie1@huawei.com>
# SPDX-License-Identifier: MulanPSL-2.0

readonly COLOR_NONE="\033[0m"
readonly COLOR_RED="\033[0;31m"
readonly COLOR_GREEN="\033[0;32m"
readonly COLOR_YELLOW="\033[0;33m"

readonly BALL_TYPES=".tar .tgz .tar.gz .zip .tar.bz2 .tar.xz .jar"

# uncompress(type, ball)
uncompress() {
    local type=$1
    local ball=$2

    case "$type" in
        ".tar")
            tar -f $ball
            ;;
        ".tgz"|".tar.gz")
            tar -zxf $ball
            ;;
        ".zip")
            unzip -q $ball
            ;;
        ".tar.bz2")
            tar -jxf $ball
            ;;
        ".tar.xz")
            tar -Jxf $ball
            ;;
        ".jar")
            unzip -q $ball -d "${ball%.*}"
            ;;
        *)
            echo "$type is not supported!"
            ;;
    esac
}

get_list() {
    local lst=""

    if [ -f "$1" ]; then
        lst=$(cat $1)
    else
        lst=$1
    fi

    echo $lst
}

# get_subdirs(dir)
get_subdirs() {
    local subdirs=$(ls -F "$1" | grep '/$' | sed 's/\///g')
    echo "$subdirs"
}

usage() {
    echo "Usage: awt [GLOBALOPTS] SUBCOMMAND [OPTS] [ARGS...]"
    echo "or: awt help SUBCOMMAND"
    echo ""
    echo "automatic work tools."
    echo "Type 'awt help <subcommand>' for help on a specific subcommand."
    echo ""
    echo "Commands:"
    echo "      findsig (fs)        Find the sig group of packages" 
    echo "      findsigowner (fso)  Find the owner of sig group" 
    echo "      findmaintainer (fm) Find the maintainers of packages" 
    echo "      genpr (gp)          Generate pr list based on package name" 
    echo "      createyaml (cy)     Create yaml file" 
    echo "      archive (ar)        Archive the packages" 
    echo "      checkballtype (cbt) Check the ball type, $BALL_TYPES are supported"
    echo "      uncompress (uc)     Uncompress ball, $BALL_TYPES are supported"
    echo "      scancopyright (scr)  Scan the copyright/software/version/license of packages"
    echo "      filterlicense (fli) Filter the license from the scancopyright result files"
    echo "      grouplicense (gli)  Grouping packages by license from the scancopyright result files"
    echo "      help (?, h)         Give detailed help on a specific sub-command"
    echo ""
    echo "Global Options:"
    echo "      -h, --help          Show this help message and exit"
    echo ""
}

usage_findsig() {
    echo "findsig (fs): Find the sig group of packages"
    echo ""
    echo "usage:"
    echo "      awt fs PKGLIST|LISTFILE"
    echo ""
}

usage_findsigowner() {
    echo "findsigowner (fso): Find the owner of sig group"
    echo ""
    echo "usage:"
    echo "      awt fso SIGNAME"
    echo ""
}

usage_findmaintainer() {
    echo "findmaintainer (fm): Find the maintainers of packages"
    echo ""
    echo "usage:"
    echo "      awt fm PKGLIST|LISTFILE"
    echo ""
}

usage_genpr() {
    echo "genpr (gp): Generate pr list based on package name"
    echo ""
    echo "usage:"
    echo "      awt gp NUMBER OUTFILE PKGLIST|LISTFILE"
    echo ""
    echo "example:"
    echo "      awt gp 1 pr.txt \"a b c\""
    echo ""
}

usage_createyaml() {
    echo "createyaml (cy): Create yaml file"
    echo ""
    echo "usage:"
    echo "      awt cy FILE.yaml"
    echo "      awt cy              # create a yaml file named by the current directory"
    echo ""
}

usage_archive() {
    echo "archive (ar): Archive the packages"
    echo ""
    echo "usage:"
    echo "      awt ar SRCDIR DSTDIR PKGLIST|LISTFILE"
    echo ""
}

usage_checkballtype() {
    echo "checkballtype (cbt): Check the ball type, $BALL_TYPES are supported"
    echo ""
    echo "usage:"
    echo "      awt cbt PROJECTDIR PKGLIST|LISTFILE"
    echo "      awt cbt PROJECTDIR"
    echo ""
}

usage_uncompress() {
    echo "uncompress (uc): Uncompress ball, $BALL_TYPES are supported"
    echo ""
    echo "usage:"
    echo "      awt uc PROJECTDIR PKGLIST|LISTFILE"
    echo "      awt uc BALLDIR"
    echo ""
}

usage_scancopyright() {
    echo "scancopyright (scr): Scan the copyright/software/version/license of packages"
    echo ""
    echo "  This command is mainly used for open source software declarations, "
    echo "  scanning Copyright, software and versions, license, etc"
    echo ""
    echo "usage:"
    echo "      awt scr PROJECTDIR PKGLIST|LISTFILE"
    echo "      awt scr PROJECTDIR"
    echo ""
    echo "notes:"
    echo "      "
    echo "  You need to unzip the packages before scanning the information."
    echo ""
    echo "  Follow these steps:"
    echo "      1) checkout the packages from obs, refers to \"obs.sh co ...\""
    echo "      2) detect whether the compressed package is a supported type, refers to \"checkballtype command\""
    echo "      3) uncompress the packages, refers to \"uncompress command\""
    echo "      4) scancopyright"
    echo ""
}

usage_filterlicense() {
    echo "filterlicense (fli): Filter the license from the scancopyright result files"
    echo ""
    echo "usage:"
    echo "      awt fli RESULTDIR"
    echo ""
}

usage_grouplicense() {
    echo "grouplicense (gli): Grouping packages by license from the scancopyright result files"
    echo ""
    echo "usage:"
    echo "      awt gli RESULTDIR"
    echo ""
}

#find_sig(sigyaml, pkg)
find_sig() {
    local sig=$(echo "$1" | grep -E "\- name|/$2\$" | grep -B1 -E "/$2\$" | head -n 1 | grep "\- name" |\
        awk -F ':' '{print $2}' | awk '{print $1}')
    echo "$sig"
}

do_findsig() {
    if [ $# != 1 ]; then
        usage_findsig; exit
    fi
    local pkgs=$(get_list "$1")
    local sigyaml="$(curl -s -X GET https://gitee.com/openeuler/community/raw/master/sig/sigs.yaml)"
    printf "%-30s %s\n" SIG PKG
    echo "---------------------------------------"
    for pkg in $pkgs; do
        sig=$(find_sig "$sigyaml" "$pkg")
        if [ -z "$sig" ]; then
            sig="Not-Found"
        fi
        printf "%-30s %s\n" $sig $pkg
    done | sort -nk1
}

# find_sigowner(sig)
find_sigowner() {
    local signame=$1
    local sigowner="$(curl -s -X GET https://gitee.com/openeuler/community/raw/master/sig/$signame/OWNERS)"

    owners=$(echo "$sigowner" | grep '^\s*-\s*' | sed 's/^\s*-\s*//')
    if [ -z "$owners" ]; then
        owners="Not-Found"
    fi
    echo "$owners"
}

do_findsigowner() {
    if [ $# != 1 ]; then
        usage_findsigowner; exit
    fi
    find_sigowner "$1"
}

# find_maintainer(sightml, sig)
# sightml="$(curl -s -X GET https://openeuler.org/en/sig.html)"
find_maintainer_deprecated() {
    local maintainer=$(echo "$1" | grep -B1 "sig/$2" | head -n 1 | grep "Maintainers" |\
        sed -e 's|,\?</div>||g' -e 's/.*Maintainers: \?//g')
    echo "$maintainer"
}

# find_maintainer(sig)
find_maintainer() {
    local owners=$(find_sigowner "$1")
    if [ "$owners" != "Not-Found" ]; then
        local maintainer=""
        for ow in $owners; do
            if [ -z "$maintainer" ]; then
                maintainer="$ow"
            else
                maintainer="$maintainer,$ow"
            fi
        done
        echo "$maintainer"
    else
        echo "$owners"
    fi
}

do_findmaintainer() {
    if [ $# != 1 ]; then
        usage_findmaintainer; exit
    fi
    local pkgs=$(get_list "$1")
    local sigyaml="$(curl -s -X GET https://gitee.com/openeuler/community/raw/master/sig/sigs.yaml)"
    printf "%s\t%s\t%s\n" PKG SIG MAINTAINER
    echo "---------------------------------------"
    for pkg in $pkgs; do
        sig=$(find_sig "$sigyaml" "$pkg")
        if [ -z "$sig" ]; then
            sig="Not-Found"
            maintainer="Not-Found"
        else
            maintainer=$(find_maintainer "$sig")
        fi
        printf "%s\t%s\t%s\n" $pkg $sig $maintainer
    done | sort -nk1

}

do_genpr() {
    if [ $# != 3 ]; then
        usage_genpr; exit
    fi
    local num=$1
    local outfile=$2
    local pkgs=$(get_list "$3")

    for pkg in $pkgs; do
        echo "https://gitee.com/src-openeuler/$pkg/pulls/$num"
    done > $outfile
}

do_createyaml() {
    yamlfile=""
    if [ $# == 1 ]; then
        yamlfile=$1
    elif [ $# == 0 ]; then
        yamlfile=$(basename $(pwd)).yaml
    else
        usage_createyaml; exit
    fi

    if [ -z "$yamlfile" ]; then
        usage_createyaml; exit
    fi

printf "\
version_control: 
src_repo: 
tag_prefix: 
separator: 
" > $yamlfile
    
    vim $yamlfile
}

do_archive() {
    if [ $# != 3 ]; then
        usage_archive; exit
    fi
    local srcdir=$1
    local dstdir=$2
    local pkgs=$(get_list "$3")

    for pkg in $pkgs; do
        mkdir -p $dstdir/$pkg
        cp $srcdir/$pkg/* $dstdir/$pkg
    done
}

do_checkballtype() {
    local prj=$1
    local pkgs=$(get_list "$3")
    if [ $# == 1 ]; then
        pkgs=$(get_subdirs "$prj")
    elif [ $# == 2 ]; then
        pkgs=$(get_list "$3")
    else
        usage_checkballtype; exit
    fi

    for pkg in $pkgs; do
        flag=0
        for t in $BALL_TYPES; do
            balls=$(ls $prj/$pkg/*$t 2> /dev/null)
            if [ -n "$balls" ]; then
                flag=1
            fi
        done
        if [ $flag == 0 ]; then
            echo "$prj/$pkg:No ball type found"
        fi
    done
}

__do_uncompress() {
    for t in $BALL_TYPES; do
        balls=$(ls *$t 2> /dev/null)
        if [ -n "$balls" ]; then
            for ball in $balls; do
                uncompress $t $ball
            done
        fi
    done
}

do_uncompress() {
    if [ $# == 1 ]; then
        pushd $1
        __do_uncompress
        popd
    elif [ $# == 2 ]; then
        local prj=$1
        local pkgs=$(get_list "$2")
        k=1
        for pkg in $pkgs; do
            echo "$k) uncompressing $prj/$pkg"
            pushd $prj/$pkg
            __do_uncompress
            popd
            ((k++))
        done
    else
        usage_uncompress; exit
    fi
}

# get_spec_tagvalue(tag, spec)
get_spec_tagvalue() {
    local value=$(sed -n "/^$1:/p" $2 | head -n 1 | awk -F ':' '{print $2}' | sed -r -e 's/\s+/ /g' -e 's/^\s*//g' -e 's/^\s*//')
    echo "$value"
}

join_copyright() {
awk -F '\n' '
BEGIN {
    flag=0;content=""
}

function is_connector(str) {
    if (str ~ /(,| (and|by|BY|By|\(?See|are|in|is|or|at|Version|for|rights))$/) {
        return 1
    } else if (str ~ /( (Free Software))$/) {
        return 1
    } else if (str ~ /^Copyright\s*(\((C|c)\)|©)?\s*[0-9,\- ]+$/) {
        return 1
    }
    return 0
}
{
    if ($1 ~ /^(\((C|c)\)|Copyright|COPYRIGHT|©)/) {
        str=$0
        if (is_connector(str)) {
            content=$0
            flag=1
        } else {
            printf("%s\n", $0)
        }
    } else {
        tmp=$0
        if (flag == 1) {
            content=content" "tmp
            if (!is_connector(content)) {
                printf("%s\n", content)
                flag=0;content=""
            }
        } else {
            printf("%s\n", tmp)
        }
    }
}'
}

do_scancopyright() {
    local prj=$1
    local pkgs=""
    if [ $# == 1 ]; then
        pkgs=$(get_subdirs "$prj")
    elif [ $# == 2 ]; then
        pkgs=$(get_list "$2")
    else
        usage_scancopyright; exit
    fi

    if [ -d result ]; then
        rm -rf result
    fi
    mkdir result

    k=1
    for pkg in $pkgs; do
        echo "$k) handling $pkg"
        spec=$(ls $prj/$pkg/*.spec)
        name=$(get_spec_tagvalue Name $spec)
        version=$(get_spec_tagvalue Version $spec)
        license=$(get_spec_tagvalue License $spec)
        raw_copyright=$(grep -rinIE '\((C|c)\)|Copyright|©' $prj/$pkg/ --exclude-dir={.git,.osc,res,bin,build} --exclude=*.java,v)
        # scan the Copyright, (C), (c), ©, including some copyright/COPYRIGHT..
        # now, cross-line Copyright is not supported incompletely
        clean_copyright=$(
            grep -A5 -rihIE '\((C|c)\)|Copyright|©' $prj/$pkg --exclude-dir={.git,.osc,res,bin,build} --exclude=*.java,v |\
            sed -e 's/^[^(©0-9a-zA-Z]*//' -e 's/[^,.>)a-zA-Z0-9]*$//' |\
            sed -r -e 's/^(dnl|m4_dnl|rem)\s*\**\s*//i' |\
            sed -r 's/(-->|<br>|<\/[a-zA-Z]+>|\\br|".*\)|"\s*\/>|\(?<A|&lt;)\s*$//' |\
            sed -r 's/(\&lt;|\\BR)\s*$//' |\
            join_copyright |\
            grep -iE '^(\((C|c)\)|Copyright|©) | ?(\(c\)\s*copyright|copyright\s*\(c\)) ' |\
            sed -r 's/(Copyright|copyright):\s*//' |\
            sed 's/\\n$//' | sed '/matches$/d' |\
            sed -r -e '/^Copyright$/d' -e '/^\((C|c)\)$/d' -e '/^Copyright\s*\((C|c)\)$/d' |\
            sed -r -e '/^Copyright\s*Notice/Id' |\
            sed 's/All rights reserved\..*$/All rights reserved./' |\
            sed -r 's/\s*-\*-[ a-zA-Z]+(-\*-)?\s*$//' |\
            sed -r 's/^hr\s*\/><p>//' |\
            grep -vE '=|\.\.\.|___*|^\((C|c)\)\s+(a|A|Any|for|notify|to|You|--|<|:) ' |\
            grep -vE '^(License:|of|copy:|[0-9a-zA-Z]+(\)|>)|[0-9]+[\.])' |\
            grep -vE 'Copyright\s+(\((C|c)\)|©)?\s*\$?(<|\[|\{)[ a-zA-Z]+(>|\]|\})' |\
            grep -vE 'Copyright\s+\\\((C|c)\\\)' |\
            grep -vE '(<|\[|\{|@+)(Year|YEAR|year)(>|\]|\}|@*)' |\
            grep -vE 'Copyright\s+(\((C|c)\)|©)?\s*(Year|YEAR|year|YYYY)' |\
            grep -vE '("|>)\s*(/|#|~|/\*|\*)*\s+(Copyright|\((C|c)\)|©)' |\
            sort -d | uniq
        )

        # output software/version/license/copyright
        {
            echo "Software: $name $version"
            echo ""
            echo "License: $license"
            echo ""
            echo "Clean-Copyright:"
            echo "$clean_copyright"
            echo ""
            echo "Raw-Copyright:"
            echo "$raw_copyright"
        } > result/$pkg.txt
        ((k++))
    done
}

# __get_licenses(result_dir)
__get_licenses() {
    local result_dir=$1
    local licenses=$(grep -rhE '^License:' $result_dir | grep -vE '\((C|c)\)|Copyright|©' |\
        awk -F ':' '{print $2}' | sed 's/^\s*//' | sed 's/ *$//' | sort -d | uniq)
    echo "$licenses"
}

do_filterlicense() {
    if [ $# != 1 ]; then
        usage_filterlicense; exit
    fi
    __get_licenses "$1"
}

# __group_license(result_dir)
__group_license() {
    local result_dir=$1
    local licenses=$(__get_licenses "$result_dir")
    licenses=$(echo "$licenses" | awk -F '\n' '{
        for (i=1;i<=NF;i++) {
            printf("\"%s\",", $i);
        }
    }')

    OLD_IFS="$IFS"
    IFS=","
    local array=($licenses)
    IFS="$OLD_IFS"

    k=1
    for ((i=0; i < ${#array[*]}; i++)); do
        lic=${array[i]}
        lic=$(echo "$lic" | sed 's/"//g')
        pkgs=$(grep -B2 -rh "^License: $lic *$" $result_dir | sed '/^\s*$/d' | sed '/--/d' | sed '/License:/d' |\
            awk -F ':' '{print $2}' | awk '{print $1}' | sort)

        echo "$k) $lic"
        for p in $pkgs; do
            printf "\t%s\n" $p
        done
        ((k++))
    done

}

do_grouplicense() {
    if [ $# != 1 ]; then
        usage_grouplicense; exit
    fi
    __group_license "$1"
}

do_help() {
    case $1 in
        "findsig"|"fs") 
            usage_findsig 
            ;;
        "findsigowner"|"fso") 
            usage_findsigowner
            ;;
        "findmaintainer"|"fm") 
            usage_findmaintainer
            ;;
        "genpr"|"gp")
            usage_genpr
            ;;
        "createyaml"|"cy") 
            usage_createyaml
            ;;
        "archive"|"ar")
            usage_archive
            ;;
        "checkballtype"|"cbt")
            usage_checkballtype
            ;;
        "uncompress"|"uc")
            usage_uncompress
            ;;
        "scancopyright"|"scr")
            usage_scancopyright
            ;;
        "filterlicense"|"fli")
            usage_filterlicense
            ;;
        "grouplicense"|"gli")
            usage_grouplicense
            ;;
        *)
            usage
            ;;
    esac
}

main() {
    local subcmd=$1
    
    if [ $# -gt 0 ]; then
        shift
    fi

    case $subcmd in
        "findsig"|"fs") 
            do_findsig "$@"
            ;;
        "findsigowner"|"fso") 
            do_findsigowner "$@"
            ;;
        "findmaintainer"|"fm") 
            do_findmaintainer "$@"
            ;;
        "genpr"|"gp")
            do_genpr "$@"
            ;;
        "createyaml"|"cy")
            do_createyaml "$@"
            ;;
        "archive"|"ar")
            do_archive "$@"
            ;;
        "checkballtype"|"cbt")
            do_checkballtype "$@"
            ;;
        "uncompress"|"uc")
            do_uncompress "$@"
            ;;
        "scancopyright"|"scr")
            do_scancopyright "$@"
            ;;
        "filterlicense"|"fli")
            do_filterlicense "$@"
            ;;
        "grouplicense"|"gli")
            do_grouplicense "$@"
            ;;
        "help"|"?"|"h")
            do_help "$@"
            ;;
        *)
            usage
            ;;
    esac

}

main "$@"

